Appearance
《C语言程序设计》第一学期重修试卷A (精选01)
一、选择题(本题共20小题,每题2分,共40分)
(1) 在 C 语言中,如果下面的变量都是 int 类型,则输出的结果是 (C)。
int sum = 5, pad = 5, pAd;
pAd = sum++;
pAd++;
++pAd;
printf("%d\n", pad);2
3
4
5
A) 7 B) 6 C) 5 D) 4
查看答案与解析
答案:C
解析: 本题考查逗号运算符、自增运算符以及变量赋值。
sum = pad = 5;:将sum和pad都初始化为 5。pAd = sum++;:后缀自增运算符++的优先级高于赋值,但它的特性是“先使用后自增”。因此先将sum的当前值(5)赋给pAd,然后sum的值变为 6。此时pAd = 5,sum = 6。pAd++;:pAd自增 1,变为 6。++pAd;:pAd自增 1,变为 7。printf("%d\n", pad);:注意这里打印的是pad,而不是pAd。变量pad的值从始至终没有被修改,依然是初始值 5。
故输出结果为 5,选 C。
难度: ⭐ 考点: #自增运算符 #变量赋值 #逗号运算符
💡 学习锦囊
📖 相关公式与知识点:
- 前缀自增
++x:先自增,后参与运算。 - 后缀自增
x++:先参与运算,后自增。
思路分析
做此类题目时,一定要看清 printf 打印的变量名。本题中 pAd 经历了一系列复杂的运算,但最后打印的却是从未改变的 pad,这是典型的“障眼法”。
易错点
- 混淆
pad和pAd,误算出pAd的最终值 7 而错选 A。
🔄 举一反三
- 若将代码改为
printf("%d\n", sum);,输出结果是什么?查看练习答案与解析
答案:6 解析:
sum在执行pAd = sum++;时发生了自增,值从 5 变为 6。
(2) 以下程序的输出结果是 (B)。
#include <stdio.h>
main()
{
int i = 010, j = 10;
printf("%d, %d\n", ++i, j--);
}2
3
4
5
6
A) 11, 10 B) 9, 10 C) 010, 9 D) 10, 9
查看答案与解析
答案:B
解析: 本题考查八进制常量以及自增自减运算符。
int i = 010;:以数字0开头的整型常量表示八进制数。八进制的010转换为十进制为 $1 \times 8^1 + 0 \times 8^0 = 8$。int j = 10;:十进制的 10。++i:前缀自增,i先变为 9,然后参与打印,输出 9。j--:后缀自减,先参与打印(输出当前值 10),然后再自减变为 9。
因此输出为 9, 10,选 B。
难度: ⭐⭐ 考点: #八进制 #自增自减运算符
💡 学习锦囊
📖 相关公式与知识点:
- 八进制数以
0开头,十六进制数以0x或0X开头。 printf("%d")以十进制形式输出。
思路分析
识别出 010 是八进制数是解题的关键,不要误以为是十进制的 10。
易错点
- 忽视前导
0,将010误认为十进制的 10。 - 混淆前缀
++和后缀--的执行顺序。
🔄 举一反三
- 若定义
int i = 0x10;,则printf("%d", i);的输出结果是什么?查看练习答案与解析
答案:16 解析:
0x10是十六进制数,转换为十进制为 $1 \times 16^1 + 0 \times 16^0 = 16$。
(3) 已知在 ASCII 代码中, 字母 A 的序号为 65 , 以下程序的输出的结果是 (D)。
#include <stdio.h>
main()
{
char c1 = 'A', c2 = 'Y';
printf("%d, %d\n", c1, c2);
}2
3
4
5
6
A) 因输出格式不合法, 输出错误信息 B) 65, 90 C) A, Y D) 65, 89
查看答案与解析
答案:D
解析: 本题考查字符型数据与整型数据的转换以及 ASCII 码。
c1 = 'A',其 ASCII 码值为 65。c2 = 'Y','Y' 与 'A' 相差 24 个字母('Y' - 'A' = 24),所以 'Y' 的 ASCII 码值为 $65 + 24 = 89$。printf("%d, %d\n", c1, c2);:使用%d格式符打印字符变量,会将字符对应的 ASCII 码值以整数形式输出。
因此输出为 65, 89,选 D。
难度: ⭐ 考点: #ASCII码 #printf格式符
💡 学习锦囊
📖 相关公式与知识点:
- 常见 ASCII 码:'A' 为 65,'a' 为 97,'0' 为 48。
%d以整数形式输出,%c以字符形式输出。
思路分析
字符在内存中是以 ASCII 码的二进制形式存储的,可以直接当作整数参与运算或按整数输出。
易错点
- 误以为打印字符必须用
%c,看到%d以为格式不合法。 - 计算 'Y' 的 ASCII 码时数错字母顺序。
🔄 举一反三
- 若
printf("%c, %c\n", c1, c2);,输出结果是什么?查看练习答案与解析
答案:A, Y 解析:使用
%c格式符会按字符形式输出。
(4) 语句 while(!E);中的条件!E 等价于 (A)。
A) E == 0 B) E != 1 C) E != 0 D) ~E
查看答案与解析
答案:A
解析: 本题考查逻辑非运算符与条件判断。
- 在 C 语言中,逻辑真用非零表示,逻辑假用 0 表示。
- 逻辑非运算符
!会将真变为假,假变为真。 - 因此,当
E为 0(假)时,!E为真(非零);当E为非零(真)时,!E为假(0)。 - 这与表达式
E == 0的逻辑一致:当E等于 0 时,表达式成立(真);当E不等于 0 时,表达式不成立(假)。
故 !E 等价于 E == 0,选 A。
难度: ⭐ 考点: #逻辑运算符 #条件判断
💡 学习锦囊
📖 相关公式与知识点:
!x等价于x == 0x(作为条件)等价于x != 0
思路分析
理解 C 语言中“非零即真,零为假”的原则是解题的关键。
易错点
- 混淆按位取反
~和逻辑非!。 - 误认为
!E等价于E != 0。
🔄 举一反三
- 语句
if(E)中的条件E等价于什么?查看练习答案与解析
答案:E != 0 解析:只要
E不为 0,条件即为真。
(5) 以下程序的输出结果是 (B)。
#include <stdio.h>
main()
{
printf("%d\n", NULL);
}2
3
4
5
A) 不确定的(因变量无定义) B) 0 C) -1 D) 1
查看答案与解析
答案:B
解析: 本题考查宏定义 NULL 的含义。
NULL是 C 语言标准库中定义的一个宏,通常表示空指针。- 在大多数编译器中,
NULL被定义为0或((void *)0)。 - 当使用
%d打印NULL时,它会被作为整数 0 输出。
故输出结果为 0,选 B。
难度: ⭐ 考点: #NULL指针 #宏定义
💡 学习锦囊
📖 相关公式与知识点:
NULL通常在<stdio.h>或<stddef.h>中定义。
思路分析
记住 NULL 在本质上等同于数值 0 即可。
易错点
- 误认为
NULL是未定义的变量导致编译错误。
🔄 举一反三
sizeof(NULL)在 64 位系统下通常是多少字节?查看练习答案与解析
答案:8 解析:
NULL本质是指针,64 位系统下指针占用 8 字节。
(6) 以下函数调用语句中含有 (B) 个实参。
func((exp1, exp2), (exp3, exp4, exp5));A) 1 B) 2 C) 4 D) 5
查看答案与解析
答案:B
解析: 本题考查逗号运算符与函数调用实参。
- 函数调用时,实参之间用逗号分隔。
- 在
func((exp1, exp2), (exp3, exp4, exp5))中,最外层的逗号将参数分隔为两部分:- 第一部分:
(exp1, exp2) - 第二部分:
(exp3, exp4, exp5)
- 第一部分:
- 每一部分都是一个由括号包裹的表达式。在 C 语言中,括号内的逗号是逗号运算符。
- 逗号运算符的规则是:从左到右依次计算各个表达式,整个表达式的值是最后一个表达式的值。
- 因此,
(exp1, exp2)作为一个整体传递给函数,是 1 个实参;(exp3, exp4, exp5)也作为一个整体传递,是 1 个实参。
故实参个数为 2,选 B。
难度: ⭐⭐ 考点: #逗号运算符 #函数实参
💡 学习锦囊
📖 相关公式与知识点:
- 函数调用语法:
函数名(实参1, 实参2, ...)。 - 逗号表达式:
(表达式1, 表达式2, ..., 表达式n),其值为表达式n的值。
思路分析
区分“作为参数分隔符的逗号”和“作为运算符的逗号”。被括号包裹的逗号属于逗号运算符,不增加参数个数。
易错点
- 简单地数逗号个数,误以为有 4 个或 5 个参数。
🔄 举一反三
func(exp1, exp2, exp3, exp4);含有几个实参?查看练习答案与解析
答案:4 解析:没有括号包裹,逗号作为参数分隔符,共 4 个实参。
(7) 下面的程序中 (C) 有错误(每行程序前面的数字是行号)。
1 #include <stdio.h>
2 main()
3 {
4 float a[3] = {0.0};
5 int i;
6 for(i = 0; i < 3; i++) s;
7 for(i = 1; i < 3; i++) a;
8 printf("%f\n", a[0]);
9 }2
3
4
5
6
7
8
9
A) 没有 B) 第4行 C) 第6行 D) 第8行
查看答案与解析
答案:C
解析: 本题考查语法错误分析。
- 第 4 行:
float a[3] = {0.0};正确,初始化数组元素为 0。 - 第 6 行:
for(i = 0; i < 3; i++) s;错误。变量s未定义,直接使用会导致编译错误(Undefined symbol 's')。 - 第 7 行:
for(i = 1; i < 3; i++) a;虽然无实际意义,但a是已定义的数组名(地址常量),在语法上是合法的表达式语句。 - 第 8 行:
printf("%f\n", a[0]);正确。
故第 6 行有错误,选 C。
难度: ⭐⭐ 考点: #语法错误 #变量未定义
💡 学习锦囊
📖 相关公式与知识点:
- 任何变量在被使用前必须先进行定义。
- 数组名在表达式中会被转换为指向数组首元素的指针。
思路分析
逐行检查语法,重点关注未定义的变量和拼写错误。
易错点
- 忽视变量
s的未定义状态。 - 误认为第 7 行的
a;是语法错误。
🔄 举一反三
- 若在第 5 行增加
int s = 0;,程序是否还有错误?查看练习答案与解析
答案:没有 解析:定义了
s之后,第 6 行的s;变为合法语句。
(8) 设有语句 int $a = 3$; 则执行了语句 $a += a -= a * a$; 后, 变量 $a$ 的值是 (D)。
A) 3 B) 0 C) 9 D) -12
查看答案与解析
答案:D
解析: 本题考查复合赋值运算符的右结合性。
- 初始状态
a = 3。 - 表达式为
a += a -= a * a。赋值运算符具有右结合性,即从右向左依次计算。 - 首先计算右侧的
a -= a * a:a * a的值为 $3 \times 3 = 9$。a -= 9等价于a = a - 9,此时a变为 $3 - 9 = -6$。
- 接着计算左侧的
a += (-6):- 此时
a的值已经变为 -6。 a += -6等价于a = a + (-6),即 $a = -6 + (-6) = -12$。
- 此时
故最终 a 的值为 -12,选 D。
难度: ⭐⭐ 考点: #复合赋值运算符 #运算符结合性
💡 学习锦囊
📖 相关公式与知识点:
- 赋值运算符(
=,+=,-=,*=等)的优先级较低,且结合性为从右到左。
思路分析
关键在于“右结合性”和“变量值的实时更新”。计算出右侧结果后,左侧运算使用的 a 已经是更新后的值了。
易错点
- 忽略右结合性,从左往右算。
- 在算左侧
a +=时,错误地使用了a的初始值 3。
🔄 举一反三
- 设
int a = 2;,执行a += a *= a;后,a的值是多少?查看练习答案与解析
答案:8 解析:先算
a *= a得a = 4。再算a += 4得a = 4 + 4 = 8。
(9) 以下的 for 循环 (C)。
for(x = 0, y = 0; (y != 123) && (x < 4); x++);A) 是无限循环 B) 循环次数不定 C) 执行 4 次 D) 执行 3 次
查看答案与解析
答案:C
解析: 本题考查 for 循环的执行次数判定。
- 循环初始化:
x = 0, y = 0。 - 循环条件:
(y != 123) && (x < 4)。 - 循环迭代:
x++。 - 循环体:为空语句(分号
;紧跟在括号后)。 - 过程分析:
- 第一次:
x=0, y=0。条件(0 != 123) && (0 < 4)为真。执行空语句,x变为 1。 - 第二次:
x=1, y=0。条件(0 != 123) && (1 < 4)为真。执行空语句,x变为 2。 - 第三次:
x=2, y=0。条件(0 != 123) && (2 < 4)为真。执行空语句,x变为 3。 - 第四次:
x=3, y=0。条件(0 != 123) && (3 < 4)为真。执行空语句,x变为 4。 - 第五次:
x=4, y=0。条件(0 != 123) && (4 < 4)为假。循环结束。
- 第一次:
循环体共被执行了 4 次,选 C。
难度: ⭐ 考点: #for循环 #循环条件
💡 学习锦囊
📖 相关公式与知识点:
for(初始化; 条件; 迭代),只要条件为假,循环立即终止。- 空语句
;也是合法的语句。
思路分析
注意 y 在循环过程中没有改变,一直是 0。因此循环的终止完全由 x < 4 决定。
易错点
- 误以为
x最终值为 3 而错选 D。 - 误以为
y != 123会导致无限循环。
🔄 举一反三
- 若将条件改为
(y != 123) || (x < 4),循环次数是多少?查看练习答案与解析
答案:无限循环 解析:因为
y一直是 0,y != 123永远为真,逻辑或||导致整体条件永远为真。
(10) 设有语句 char a = '\72'; 则变量 a (A)。
A) 包含 1 个字符 B) 包含 2 个字符 C) 包含 3 个字符 D) 说明不合法
查看答案与解析
答案:A
解析: 本题考查转义字符的识别。
'\72'是一个转义字符。- 以反斜杠
\开头,后面跟着 1 到 3 位八进制数的字符常量表示转义字符。 \72表示八进制数 72 对应的字符。- 无论转义字符的形式多么复杂,它在内存中都只占用 1 个字节,表示 1 个字符。
故选 A。
难度: ⭐ 考点: #转义字符 #char类型
💡 学习锦囊
📖 相关公式与知识点:
- 八进制转义字符:
\ddd(1-3位八进制数)。 - 十六进制转义字符:
\xhh(1-2位十六进制数)。
思路分析
转义字符虽然书写上有多个字符,但本质上代表的是一个单一的 ASCII 字符。
易错点
- 把
\、7、2当成 3 个独立的字符。
🔄 举一反三
- 语句
char a = '\x41';中变量a包含几个字符?查看练习答案与解析
答案:1 个 解析:
\x41是十六进制转义字符,代表字符 'A',占 1 个字符。
(11) C 语言中 (D)。
A) 不能使用 do-while 语句构成的循环 B) do-while 语句构成的循环必须用 break 语句才能退出 C) do-while 语句构成的循环,当 while 语句中的表达式值为非零时结束循环 D) do-while 语句构成的循环,当 while 语句中的表达式值为零时结束循环
查看答案与解析
答案:D
解析: 本题考查 do-while 循环的执行机制。
do-while循环的语法结构为:do { 循环体 } while (表达式);。- 它的特点是“先执行,后判断”。无论条件如何,循环体至少会被执行一次。
- 循环的继续与结束取决于
while后面的表达式:当表达式的值为**真(非零)时,继续循环;当表达式的值为假(零)**时,结束循环。
故选 D。
难度: ⭐ 考点: #do-while循环 #循环控制
💡 学习锦囊
📖 相关公式与知识点:
while循环:先判断,后执行。do-while循环:先执行,后判断(至少执行一次)。
思路分析
牢记 C 语言中条件判断的本质:非零为真继续,零为假退出。
易错点
- 误以为
do-while循环在条件为假时才继续。
🔄 举一反三
- 下面代码的输出结果是什么?c
int i = 5; do { printf("%d", i); } while(0);1
2
3
4查看练习答案与解析
答案:5 解析:条件为 0(假),但
do-while先执行一次,打印 5 后退出。
(12) 以下程序的输出结果是 (A)。
#include <stdio.h>
#include <string.h>
main()
{
char str[12] = {'s', 't', 'r', 'i', 'n', 'g'};
printf("%d\n", strlen(str));
}2
3
4
5
6
7
A) 6 B) 7 C) 11 D) 12
查看答案与解析
答案:A
解析: 本题考查数组初始化与 strlen 函数。
char str[12] = {'s', 't', 'r', 'i', 'n', 'g'};:定义了一个长度为 12 的字符数组。显式初始化了前 6 个元素。- 根据 C 语言规则,部分初始化的数组,未显式初始化的元素会被自动赋值为该类型的零值。对于字符数组,零值即为空字符
\0。 strlen(str)函数用于计算字符串的长度,其机制是从字符串首地址开始计数,直到遇到第一个空字符\0为止(不包含\0)。- 数组内容为
's', 't', 'r', 'i', 'n', 'g', '\0', ...。strlen计数的字符个数为 6。
故输出结果为 6,选 A。
难度: ⭐⭐ 考点: #strlen函数 #数组初始化
💡 学习锦囊
📖 相关公式与知识点:
strlen返回的是有效字符个数。sizeof返回的是整个数组占用的内存字节数。
思路分析
明确 strlen 和 sizeof 的区别。本题中 sizeof(str) 为 12,而 strlen(str) 为 6。
易错点
- 混淆
strlen和sizeof。
🔄 举一反三
- 若将代码改为
printf("%d", sizeof(str));,输出结果是什么?查看练习答案与解析
答案:12 解析:
sizeof计算整个数组的内存大小,长度为 12。
(13) 以下程序的输出结果是 (A)。
#include <stdio.h>
main()
{
int a = 2, c = 5;
printf("a=%%%d,b=%%%d\n", a, c);
}2
3
4
5
6
A) a=%2,b=%5 B) a=2,b=5 C) a=%%d,b=%%d D) a=%d,b=%d
查看答案与解析
答案:A
解析: 本题考查 printf 中百分号 % 的转义输出。
- 在
printf的格式控制字符串中,%是格式说明符的起始标志。 - 如果想要在屏幕上打印出一个
%字符,需要使用两个连续的百分号%%来表示转义。 - 在字符串
"a=%%%d,b=%%%d\n"中:- 前两个
%组合成%%,输出一个%。 - 第三个
%与后面的d组合成%d,输出对应变量的值(a的值 2)。 - 组合起来就是
a=%2。同理,后半部分输出b=%5。
- 前两个
故输出为 a=%2,b=%5,选 A。
难度: ⭐⭐ 考点: #printf格式化输出 #百分号转义
💡 学习锦囊
📖 相关公式与知识点:
- 在
printf中,%%用于输出一个%。
思路分析
理清格式控制字符串中 % 的两两配对关系。
易错点
- 误以为
%%d会直接打印出%d文本。
🔄 举一反三
printf("%%d");的输出结果是什么?查看练习答案与解析
答案:%d 解析:
%%转义为%,后面跟着普通字符d。
(14) 以下程序的输出结果是 (B)。
#include <stdio.h>
main()
{
int a, b, d = 241;
a = d / 100 % 9;
b = (-1) && (-1);
printf("%d,%d\n", a, b);
}2
3
4
5
6
7
8
A) 6,1 B) 2,1 C) 6,0 D) 2,0
查看答案与解析
答案:B
解析: 本题考查算术运算与逻辑运算。
d / 100:整型除法,$241 / 100 = 2$。2 % 9:求余运算,商 0 余 2,所以a = 2。b = (-1) && (-1):逻辑与运算。在 C 语言中,非零值即为真。-1为真,真 && 真的结果为真(1)。所以b = 1。printf打印出2,1。
故选 B。
难度: ⭐ 考点: #整型除法 #求余运算 #逻辑与
💡 学习锦囊
📖 相关公式与知识点:
- 整数相除只保留整数部分。
- 逻辑运算的结果只有 0(假)和 1(真)。
思路分析
注意 C 语言中负数(如 -1)在逻辑判断中也是“真”。
易错点
- 误以为
-1是假。
🔄 举一反三
- 若
b = (-1) || (0);,b的值是多少?查看练习答案与解析
答案:1 解析:
-1为真,逻辑或运算只要有一个为真即为 1。
(15) 以下 for 语句构成的循环执行了 (C) 次。
#include <stdio.h>
#define N 2
#define M N+1
#define NUM (M + 1)*M / 2
main()
{
int i, n = 0;
for (i = 1; i <= NUM; i++);
{
n++;
printf("%d", n);
}
printf("\n");
}2
3
4
5
6
7
8
9
10
11
12
13
14
A) 5 B) 6 C) 8 D) 9
查看答案与解析
答案:C
解析: 本题考查宏定义的文本替换机制。
- 宏替换是纯文本替换,不带括号。
NUM展开过程:NUM=(M + 1)*M / 2- 替换
M:(N+1 + 1)*N+1 / 2 - 替换
N:(2+1 + 1)*2+1 / 2
- 计算展开后的表达式:
NUM=(4)*2 + 1/2- 根据优先级,先算乘除,后算加法:
4 * 2 = 8,1 / 2 = 0。 NUM=8 + 0 = 8。
for (i = 1; i <= 8; i++);循环从i=1执行到i=8,共执行了 8 次。
故选 C。
难度: ⭐⭐⭐ 考点: #宏替换 #运算符优先级
💡 学习锦囊
📖 相关公式与知识点:
- 宏定义只是简单的文本替换,一定要注意运算符的结合优先级,必要时在宏定义中加括号。
思路分析
宏替换千万不能先计算宏的值,必须先原样展开表达式,再按优先级计算。
易错点
- 先入为主地算出 $M = 3$,然后带入 $NUM = 4 * 3 / 2 = 6$。
🔄 举一反三
- 若宏定义为
#define NUM ((M+1)*M/2),展开后的值是多少?查看练习答案与解析
答案:6 解析:带括号后,表达式变为
((2+1+1)*(2+1)/2),即4 * 3 / 2 = 6。
(16) 设有以下语句, 则 (D) 不是对 a 数组元素的正确引用, 其中 $0 \leq i < 10$。
int a[10] = {0,1,2,3,4,5,6,7,8,9}, *p = a;A) a[p - a] B) *(&a[i]) C) p[i] D) ((a + i))
查看答案与解析
答案:D
解析: 本题考查指针与数组元素的引用。
- A 选项:
p - a是指针相减,结果为 0。a[0]是对首元素的正确引用。 - B 选项:
&a[i]取得第i个元素的地址,再解引用*,等价于a[i]。正确。 - C 选项:
p指向数组首地址,指针可以像数组名一样通过下标引用,p[i]等价于a[i]。正确。 - D 选项:
a + i是第i个元素的地址,*(a + i)已经取出了该元素的值(整型)。再次对整型使用解引用运算符*(*(a + i))是非法的。
故选 D。
难度: ⭐⭐ 考点: #指针与数组 #解引用
💡 学习锦囊
📖 相关公式与知识点:
a[i]$\Leftrightarrow$*(a + i)
思路分析
注意解引用的层数,对非指针类型使用解引用 * 是语法错误。
易错点
- 混淆了指针地址的增加与解引用的关系。
🔄 举一反三
- 表达式
*(p + i)是否是对a[i]的正确引用?查看练习答案与解析
答案:是 解析:
p指向首地址,p+i即为a[i]的地址,解引用得到元素本身。
(17) 以下程序的输出结果是 (B)。
#include <stdio.h>
main()
{
int i = 1, j = 3;
printf("%d", i++);
{
int i = 0;
i += j * 2;
printf("%d,%d", i, j);
}
printf("%d,%d\n", i, j);
}2
3
4
5
6
7
8
9
10
11
12
A) 1,6,3,1,3 B) 1,6,3,2,3 C) 1,6,3,6,3 D) 1,7,3,2,3
查看答案与解析
答案:B
解析: 本题考查局部变量的作用域与遮蔽。
- 外层定义
i = 1, j = 3。 printf("%d", i++);打印外层i的当前值 1,随后外层i自增变为 2。- 进入内层复合语句(花括号):
- 重新定义了局部变量
int i = 0;,这会遮蔽外层的i。 i += j * 2:内层i变为 $0 + 3 \times 2 = 6$。printf打印内层i和j(内层无j,使用外层),输出6,3。
- 重新定义了局部变量
- 退出复合语句,内层
i销毁,外层i重新可见。 printf打印外层i(值为 2)和j(值为 3),输出2,3。- 合并输出为
16,32,3。
故选 B。
难度: ⭐⭐ 考点: #变量作用域 #作用域遮蔽
💡 学习锦囊
📖 相关公式与知识点:
- 复合语句内部定义的变量生命周期仅限于该语句块。
思路分析
注意进入花括号后,新定义的同名变量会使外层的同名变量在当前块内不可见。
易错点
- 混淆内外层
i的值变化,以为外层i也变成了 6。
🔄 举一反三
- 若将内层
int i = 0;改为i = 0;,最终输出结果是什么?查看练习答案与解析
答案:1,6,3,6,3 解析:没有新定义变量,修改的就是外层的
i。
(18) 以下程序的输出结果是 (A)。
#include <stdio.h>
int func(int a, int b)
{
static int m = 0, i = 2;
i += m + 1;
m = i + a + b;
return m;
}
main()
{
int k = 4, m = 1, p;
p = func(k, m);
printf("%d,", p);
p = func(k, m);
printf("%d\n", p);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
A) 8,17 B) 8,16 C) 8,20 D) 8,8
查看答案与解析
答案:A
解析: 本题考查 static 静态局部变量。
- 第一次调用
func(4, 1):- 静态变量
m=0, i=2初始化。 i += 0 + 1$\Rightarrow$i = 3。m = 3 + 4 + 1 = 8。- 返回 8,打印
8,。
- 静态变量
- 第二次调用
func(4, 1):- 静态变量保留上次的值,即
m=8, i=3。不再执行初始化。 i += 8 + 1$\Rightarrow$i = 12。m = 12 + 4 + 1 = 17。- 返回 17,打印
17。
- 静态变量保留上次的值,即
故输出为 8,17,选 A(原题答案 D 存在逻辑错误,修正为 A)。
难度: ⭐⭐⭐ 考点: #静态局部变量 #函数调用
💡 学习锦囊
📖 相关公式与知识点:
static变量只在程序加载时初始化一次,并在多次调用间持久保存其值。
思路分析
每次调用函数时,静态变量都在上一次运算的终值基础上继续计算。
易错点
- 每次调用都对
m和i重新赋初值。
🔄 举一反三
- 若去掉
static关键字,输出结果是什么?查看练习答案与解析
答案:8,8 解析:变为常规局部变量,每次调用都重新初始化。
(19) 设有以下语句:
char str1[] = "string", str2[8], *str3, *str4 = "string";则 (D) 不是对库函数 strcpy 的正确调用。
A) strcpy(str1,"HELLO1"); B) strcpy(str2,"HELLO2"); C) strcpy(str3,"HELLO3"); D) strcpy(str4,"HELLO4");
查看答案与解析
答案:D
解析: 本题考查 strcpy 函数的使用以及内存权限。
strcpy的原型为char *strcpy(char *dest, const char *src);,其功能是将源字符串复制到目标地址中。目标地址必须是可写的且有足够的空间。- D 选项:
str4指向一个字符串常量"string"。字符串常量存放在只读数据段。尝试使用strcpy修改只读内存会引发“内存写入违规”崩溃。
注:C 选项中 str3 是野指针,写入也是未定义行为。但从考点来看,D 选项考查字符串常量不能修改的知识点更为明确。
故选 D。
难度: ⭐⭐⭐ 考点: #strcpy函数 #字符串常量 #指针安全性
💡 学习锦囊
📖 相关公式与知识点:
- 字符串常量位于代码区(只读),不能被修改。
- 数组名是地址常量,其指向的内存是可写的。
思路分析
检查目的地址是否具有写权限。
易错点
- 误认为指针只要指向了字符串就可以随意修改。
🔄 举一反三
strcpy(str1, "A");是否正确?查看练习答案与解析
答案:正确 解析:
str1空间足够,且可以被覆写。
(20) C 语言中形参的缺省存储类别是 (A)。
A) 自动(auto) B) 静态(static) C) 寄存器(register) D) 外部(extern)
查看答案与解析
答案:A
解析: 本题考查 C 语言变量存储类别。
- 在 C 语言中,函数的形参在函数调用时分配内存,函数执行完毕后自动销毁。
- 因此,形参的默认存储类别是
auto(自动变量),通常存储在栈区。
故选 A。
难度: ⭐ 考点: #存储类别 #形参
💡 学习锦囊
📖 相关公式与知识点:
auto:自动变量(默认)。static:静态变量。extern:外部声明。register:寄存器变量。
思路分析
识记基础概念即可。
易错点
- 混淆了局部变量、形参的生存期。
🔄 举一反三
- 全局变量的缺省存储类别是什么?
查看练习答案与解析
答案:extern(外部变量) 解析:全局变量默认具有外部链接属性。
二、填空题(本题共6空,每空5分,共30分)
(1) 以下程序求 a 数组中的所有素数的和,函数 isprime 用来判断自变量是否为素数。素数是只能被 1 和本身整除且大于 1 的自然数。
#include <stdio.h>
main()
{
int i, a[10], *p = a, sum = 0;
printf("Enter 10 num:\n");
for (i = 0; i < 10; i++)
scanf("%d", &a[i]);
for (i = 0; i < 10; i++)
if (isprime(*(p + ___①___)) == 1)
{
printf("%d", *(a + i));
sum += *(a + i);
}
printf("\nThe sum=%d\n", sum);
}
int isprime(int x)
{
int i;
for (i = 2; i <= x / 2; i++)
if (x % i == 0)
return (0);
return (1);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
查看答案与解析
答案:① i
解析:p 指向数组 a 的首元素,*(p + i) 等价于 a[i],即访问数组第 i 个元素。循环遍历数组,对每个元素调用 isprime 判断是否为素数。
难度: ⭐⭐ 考点: #指针与数组 #素数判断
💡 学习锦囊
📖 相关公式与知识点:
*(p + i)等价于p[i]等价于a[i](当 p=a 时)。- 素数判断:从 2 到 x/2 检查是否有因子。
思路分析
指针 p 已指向数组首地址,通过 p+i 偏移访问各元素。
🔄 举一反三
- 若将
*(p + i)改为p[i],功能是否相同?查看练习答案与解析
答案:相同 解析:
*(p+i)和p[i]在 C 语言中完全等价。
(2) 以下程序调用 invert 函数按逆序重新放置 a 数组中元素的值。a 数组中的值在 main 函数中读入。
#include <stdio.h>
#define N 10
void invert(int *s, int i, int j)
{
int t;
if (i < j)
{
t = *(s + i);
*(s + i) = *(s + j);
*(s + j) = t;
invert(s, ___②___, j - 1);
}
}
main()
{
int a[N], i;
for (i = 0; i < N; i++)
scanf("%d", a + ___③___);
invert(a, 0, N - 1);
for (i = 0; i < N; i++)
printf("%d", a[i]);
printf("\n");
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
查看答案与解析
答案:② i + 1(或 ++i) ③ i
解析: ② invert 是递归函数,交换 s[i] 和 s[j] 后,递归处理子数组 s[i+1 ... j-1],所以第二个参数应为 i+1。③ scanf 需要地址,a + i 即 &a[i]。
难度: ⭐⭐⭐ 考点: #递归 #数组逆序 #指针
💡 学习锦囊
📖 相关公式与知识点:
- 递归三要素:终止条件(i≥j)、递归体(交换+递归调用)、参数变化(i+1, j-1)。
a + i等价于&a[i]。
思路分析
递归逆序:每次交换首尾元素,然后对去掉首尾的子数组递归。
🔄 举一反三
- 用循环实现数组逆序,如何写?
查看练习答案与解析
答案:
cfor (i = 0, j = N-1; i < j; i++, j--) { t = a[i]; a[i] = a[j]; a[j] = t; }1
2
(3) 以下程序的功能是将字符串 a 中下标值为偶数的元素由小到大排序,其他元素不变。
#include <stdio.h>
main()
{
char a[] = "labchmfye", t;
int i, j;
for (i = 0; i < 7; i += 2)
for (j = i + 2; j < 9; ___④___)
if (___⑤___)
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
puts(a);
printf("\n");
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
查看答案与解析
答案:④ j += 2 ⑤ a[i] > a[j]
解析: ④ 只对偶数下标排序,所以 j 的步长也是 2。⑤ 选择排序的比较条件:如果前面的元素大于后面的元素则交换,实现升序排列。
难度: ⭐⭐ 考点: #选择排序 #字符串
💡 学习锦囊
📖 相关公式与知识点:
- 选择排序:每次找到最小元素放到前面。
- 只对特定下标排序时,步长相应调整。
思路分析
偶数下标:0, 2, 4, 6, 8。i 从 0 开始步长 2,j 从 i+2 开始步长 2。
🔄 举一反三
- 若要对奇数下标元素排序,如何修改?
查看练习答案与解析
答案:i 从 1 开始,步长仍为 2。
三、阅读程序题(本题共4小题,每题5分,共20分)
(1) 阅读下列程序:
#include <stdio.h>
main()
{
int i, j, row, column, m;
static int array[3][3] = {{100, 200, 300}, {28, 72, -30}, {-850, 2, 6}};
m = array[0][0];
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
if (array[i][j] < m)
{
m = array[i][j];
row = i;
column = j;
}
printf("%d,%d,%d\n", m, row, column);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上述程序的输出结果是_____。
查看答案与解析
答案: -850,2,0
解析: 程序遍历 3×3 二维数组,寻找最小值。初始 m=100(array[0][0])。遍历过程中:28<100→m=28;-30<28→m=-30;-850<-30→m=-850。最终最小值 -850 位于 array[2][0],即 row=2, column=0。
难度: ⭐⭐ 考点: #二维数组 #求最值
💡 学习锦囊
📖 相关公式与知识点:
- 求最小值:初始化 m 为第一个元素,遍历比较更新。
static修饰的局部数组在数据段分配内存。
思路分析
逐元素比较,记录最小值和位置。
🔄 举一反三
- 若将
if (array[i][j] < m)改为if (array[i][j] > m),输出什么?查看练习答案与解析
答案:
300,0,2解析:改为求最大值,最大值为 300,位于 array[0][2]。
(2) 下面程序的输出结果是_____。
#include <stdio.h>
main()
{
int a = 3, b = 2, c = 1;
c -= ++b;
b *= a + c;
{
int b = 5, c = 12;
c /= b * 2;
a = c;
printf("%d,%d,%d,", a, b, c);
a += --c;
}
printf("%d,%d,%d\n", a, b, c);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
查看答案与解析
答案: 1,5,1,2,3,-2
解析: 外层:++b 使 b=3,c -= 3 即 c=1-3=-2。a+c = 3+(-2)=1,b *= 1 即 b=3。进入内层块:定义局部 b=5, c=12。c /= b*2 即 c=12/10=1(整数除法)。a=c=1(修改外层 a)。打印 1,5,1,。a += --c 即 a=1+0=1。退出内层,外层 b=3, c=-2。打印 1,3,-2。合并:1,5,1,2,3,-2。
难度: ⭐⭐⭐ 考点: #作用域 #复合赋值 #整数除法
💡 学习锦囊
📖 相关公式与知识点:
- 内层块中同名变量遮蔽外层变量。
- 整数除法截断小数。
思路分析
分内外层分别追踪变量值,注意内层修改外层 a 的影响。
易错点
- 混淆内外层 b、c 的值。
🔄 举一反三
- 若去掉内层的
int b=5, c=12;声明,输出结果是什么?查看练习答案与解析
答案:
0,3,0,0,3,-2解析:内层直接使用外层变量,c=(-2)/(3*2)=0(整数除法)。
(3) 请读程序:
#define PR(ar) printf("%d", ar)
main()
{
int j, a[] = {1, 3, 5, 7, 9, 11, 13, 15}, *p = a + 5;
for (j = 3; j; j--)
{
switch (j)
{
case 1:
case 2:
PR(*p++);
break;
case 3:
PR(*(--p));
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上面程序的输出结果是_____。
查看答案与解析
答案: 9911
解析: 初始 p=a+5 指向 a[5]=11。循环 j=3,2,1:
- j=3:case 3,
--p使 p 指向 a[4]=9,PR(*(--p))输出 9。 - j=2:case 2,
PR(*p++)输出当前 *p=9,然后 p++ 指向 a[5]=11。 - j=1:case 1(无 break 穿透到 case 2),
PR(*p++)输出 11,p++ 指向 a[6]=13。
合并输出:9911。
难度: ⭐⭐⭐ 考点: #switch穿透 #指针运算 #宏定义
💡 学习锦囊
📖 相关公式与知识点:
- switch 中若无 break,会穿透到下一个 case。
*p++:先取 *p,再 p++。*(--p):先 --p,再取 *p。
思路分析
逐轮追踪 p 的位置变化和输出值。
易错点
- 混淆
*p++(后缀++优先级高于*,但后缀效果是先用后增)和(*p)++。
🔄 举一反三
- 若将
*p++改为(*p)++,输出结果是什么?查看练习答案与解析
答案:
9,10,12(数组元素被修改) 解析:(*p)++先取 *p 的值输出,然后对该元素自增。
(4) 下面程序的输出是_____。
long fun5(int n)
{
long s;
if ((n == 1) || (n == 2))
s = 2;
else
s = n + fun5(n - 1);
return s;
}
main()
{
long x;
x = fun5(4);
printf("%ld\n", x);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
查看答案与解析
答案: 9
解析: 递归展开:fun5(4) = 4 + fun5(3) = 4 + (3 + fun5(2)) = 4 + 3 + 2 = 9。
难度: ⭐⭐ 考点: #递归 #函数调用
💡 学习锦囊
📖 相关公式与知识点:
- 递归公式:f(1)=f(2)=2,f(n)=n+f(n-1)(n>2)。
- 展开:f(4)=4+f(3)=4+3+f(2)=4+3+2=9。
思路分析
从顶层逐层展开,直到终止条件 n=1 或 n=2。
🔄 举一反三
- fun5(5) 的值是多少?
查看练习答案与解析
答案:14 解析:5+4+3+2=14。
四、程序题(10分)
- 输入两个整数,求他们相除的余数,用带参数的宏来编程实现。
查看答案与解析
参考答案:
#include <stdio.h>
#define MOD(a, b) ((a) % (b))
main()
{
int x, y;
printf("请输入两个整数: ");
scanf("%d %d", &x, &y);
printf("%d %% %d = %d\n", x, y, MOD(x, y));
}2
3
4
5
6
7
8
9
10
解析: 带参数的宏 MOD(a, b) 在预处理阶段展开为 ((a) % (b))。宏参数用括号包裹防止运算符优先级问题。%% 在 printf 中输出 % 字符。
难度: ⭐⭐ 考点: #带参数宏 #求余运算
💡 学习锦囊
📖 相关公式与知识点:
- 带参数宏:
#define 宏名(参数列表) 替换文本 - 宏参数建议加括号:
((a) % (b))而非a % b
思路分析
宏在预处理阶段进行文本替换,不是函数调用,没有类型检查。
易错点
- 宏参数不加括号,如
#define MOD(a,b) a%b,当调用MOD(x+1, y)时展开为x+1%y,结果错误。
🔄 举一反三
- 用带参数宏实现求两个数的最大值。
查看练习答案与解析
答案:
#define MAX(a, b) ((a) > (b) ? (a) : (b))解析:三目运算符配合括号确保安全。